/****************************************************************
 * * Product  :   HP Subscriber Network Application Policy
 * * Module   :   gr-manager
 * * Date: Apr 10, 2015
 * * Author: Joey Yi
 * * (C) Copyright 2015, Hewlett-Packard Company, All Rights Reserved.
 * * This software is the proprietary information of HP, Inc.
 * * Use is subject to license terms.
 * ****************************************************************
 * * Description:
 * * initialize some service objects and as a program entrance.
 ****************************************************************/
package com.hp.snap.gr;

import java.io.File;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.codehaus.groovy.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.hp.snap.gr.exception.ActionException;
import com.hp.snap.gr.exception.BusinessException;
import com.hp.snap.gr.exception.GRMException;
import com.hp.snap.gr.model.TaskGroup;
import com.hp.snap.gr.model.TaskTypes;
import com.hp.snap.gr.task.GRMTaskService;
import com.hp.snap.gr.task.impl.GRSiteTaskServiceImpl;
import com.hp.snap.gr.utils.Constants;
import com.hp.snap.gr.utils.FileUtils;
import com.hp.snap.gr.utils.GRMConfigManager;
import com.hp.snap.gr.utils.eium.JMXClientUtils;

import static com.hp.snap.gr.utils.Constants.CONSOLE;

/**
 * Initialize some service objects and as a program entrance.
 * Date: 2016/1/15
 **/
public class GRMLauncher {

    public static final int RESULT_SUCCESS = 0;
    public static final int RESULT_CMD_ERROR = 1;
    public static final int RESULT_TASK_FAIL = 2;
    public static final int RESULT_TASK_ABORT = 3;
    public static final int RESULT_TASK_RUNNING = 4;
    private static Logger logger = LoggerFactory.getLogger(GRMLauncher.class);
    private static Map<TaskGroup, GRMTaskService> TASK_GROUP_SERVICES = new HashMap<TaskGroup, GRMTaskService>();

    static {
        TASK_GROUP_SERVICES.put(TaskGroup.GRSITE, new GRSiteTaskServiceImpl());
    }

    public static void main(String[] args) throws Exception {

        String taskGroup = args.length > 0 ? args[0] : "<TASK_GROUP>";

        String taskId = "";
        String fileName = "";
        String url1 = "";
        String url2 = "";
        String user = "";
        String password = "";

        // for each shell tool, we always set a fix value, e.g. SGM, SGR, SGS
        if (args.length != 3 && args.length != 4) {
            showUsage(taskGroup);
            writeStatusAndExitSystem(RESULT_CMD_ERROR, fileName, taskId);
        }

        TaskGroup tg = null;
        TaskTypes taskType = null;

        // show command usage
        if (args.length == 3 || args.length == 4) {
            Map<String, String> temp = new HashMap<String, String>();
            if (args.length == 4) {
                fileName = args[2];
                logger.info("fileName is " + fileName);
                logger.info("params is " + args[3]);
                //                taskid=xx, url1=xx,url2=xx,user=xx,password=xx
                String userInfo[] = args[3].split(",");
                for (String infos : userInfo) {
                    String[] info = infos.split("=");
                    if (info.length == 2) {
                        temp.put(info[0].toLowerCase(), info[1]);
                    }
                }
            } else {
                fileName = "temp";
                temp = GRMConfigManager.getConfig();
            }
            taskId = temp.get(Constants.GET_SESSIONSERVER_CONFIG_TASKID.toLowerCase());
            logger.debug("set taskId value is " + taskId);
            url1 = temp.get(Constants.GET_SESSIONSERVER_CONFIG_URL1.toLowerCase());
            logger.debug("set url1 value is " + url1);
            url2 = temp.get(Constants.GET_SESSIONSERVER_CONFIG_URL2.toLowerCase());
            logger.debug("set url2 value is " + url2);
            user = temp.get(Constants.GET_SESSIONSERVER_CONFIG_USER.toLowerCase());
            logger.debug("set user value is " + user);
            password = temp.get(Constants.GET_SESSIONSERVER_CONFIG_PASSWORD.toLowerCase());
            logger.debug("set password value is " + password);

            try {
                tg = TaskGroup.valueOf(args[0]);
                taskGroup = tg.toString();
            } catch (IllegalArgumentException e) {
                logger.error("Task Group [" + taskGroup + "] not supported!");
                showUsage("<TASK_GROUP>");
                writeStatusAndExitSystem(RESULT_CMD_ERROR, fileName, taskId);
            }
            String task = (taskGroup + "_" + args[1]).toUpperCase();
            try {
                taskType = TaskTypes.valueOf(task);
            } catch (IllegalArgumentException e) {
                CONSOLE.info("Command Error.");
                showUsage(taskGroup);
                writeStatusAndExitSystem(RESULT_CMD_ERROR, fileName, taskId);
            }
        }

        // execute task
        if (tg != null && taskType != null) {
            logger.info("Executing task [" + taskType + "] ...");

            CONSOLE.info("Executing task [" + taskType + "] ...");

            GRMTaskService taskService = TASK_GROUP_SERVICES.get(tg);
            if (taskService != null) {
                try {
                    if (!writeStatus(RESULT_TASK_RUNNING, fileName, taskId)) {
                        exitSystem(RESULT_TASK_FAIL);
                    }

                    taskService.setGlobalValue(user, password, url1, url2, fileName, taskId, StringUtils.isEmpty(user)?"":args[3]);
                    boolean result = taskService.handle(taskType);
                    if (!result) {
                        logger.error("Task [{}] execution failed!", taskType);
                        rollbackErrorStatus(taskService, taskType, RESULT_TASK_FAIL, fileName, taskId);
                    }
                } catch (GRMException e) {
                    logger.error("Task [" + taskType + "] execution failed: ", e);
                    rollbackErrorStatus(taskService, taskType, RESULT_TASK_FAIL, fileName, taskId);
                } catch (ActionException e) {
                    logger.error("Task [" + taskType + "] execute failed: ", e);
                    if (e instanceof BusinessException) {
                        CONSOLE.info(e.getMessage());
                        writeStatusAndExitSystem(RESULT_TASK_ABORT, fileName, taskId);
                    } else {
                        rollbackErrorStatus(taskService, taskType, RESULT_TASK_FAIL, fileName, taskId);
                    }
                } catch (Throwable e) {
                    logger.error("Task [" + taskType + "] execution failed: ", e);
                    rollbackErrorStatus(taskService, taskType, RESULT_TASK_FAIL, fileName, taskId);
                }
            } else {
                logger.warn("Task group [" + tg + "] has no implementation!");
            }
        }

        logger.info("Task [{}] executed successfully!", taskType);

        writeStatusAndExitSystem(RESULT_SUCCESS, fileName, taskId);

    }

    /**
     * show usage in command line.
     *
     * @param taskGroup defined task group name,GRSITE
     */
    private static void showUsage(String taskGroup) {
        String cmd = "java -jar gr-manager.jar " + taskGroup + " <TASK_NAME>";
        if (TaskGroup.GRSITE.toString().equals(taskGroup)) {
            cmd = "SNAP-GR-SMAN.sh [start|stop|run|pause|getStatus|getServer|checkProcess|checkIMDB|checkLog|checkNode]";
        }
        CONSOLE.info("Usage: " + cmd);
    }

    /**
     * write task status to files and exit system.
     *
     * @param status
     * @param fileName
     * @param taskId
     */
    public static void writeStatusAndExitSystem(int status, String fileName, String taskId) {
        if (!writeStatus(status, fileName, taskId)) {
            exitSystem(RESULT_TASK_FAIL);
        }
        exitSystem(status);
    }

    /**
     * if task execute failed and it has changed GR Status, it will roll back GR Status to error.
     */
    public static void rollbackErrorStatus(GRMTaskService taskService, TaskTypes taskType, int status, String fileName,
            String taskId) {
        String task = taskType.toString().toLowerCase();
        if (!task.contains("check") && !task.contains("get")) {
            try {
                taskService.handle(TaskTypes.GRSITE_ROLLBACK);
            } catch (GRMException | ActionException e) {
                logger.error(e.toString());
            }
        }
        writeStatusAndExitSystem(status, fileName, taskId);
    }

    /**
     * write task status to files
     *
     * @param status
     * @param fileName
     * @param taskId
     */
    public static boolean writeStatus(int status, String fileName, String taskId) {
        if (null != taskId && taskId.length() != 0) {
            StringBuffer stringBuffer = new StringBuffer();
            stringBuffer.append(status);
            logger.info("output status file name :" + Constants.USER_GR_TEMP + File.separator + fileName + ".status");
            return FileUtils
                    .writeFile(stringBuffer.toString(), Constants.USER_GR_TEMP + File.separator + fileName + ".status");
        } else {
            return true;
        }
    }

    /**
     * Show the exit console log and exit system.
     *
     * @param status 0: task execute successful
     *               1: task command error
     *               2: task execute failed
     *               3: task execute aborted
     */
    public static void exitSystem(int status) {

        if (RESULT_TASK_FAIL == status) {
            CONSOLE.info("Task execution failed!");
        } else if (RESULT_SUCCESS == status) {
            CONSOLE.info("Task execution successful!");
        } else if (RESULT_TASK_ABORT == status) {
            CONSOLE.info("Task execution aborted!");
        }

        try {
            JMXClientUtils.destroy();
        } catch (Exception e) {
            // do nothing
        }

        System.exit(status);
    }
}
